/*
 * @(#)DigestInputStream.java	1.30 01/12/12
 *
 * 版权所有2002 Sun MicroSystems，Inc.保留所有权利。Sun专有/机密。使用受许可条款的约束。
 */

package java.security;

import java.io.IOException;
import java.io.EOFException;
import java.io.InputStream;
import java.io.FilterInputStream;
import java.io.PrintStream;
import java.io.ByteArrayInputStream;

/** 
 * 使用流经该流的比特更新关联消息摘要的透明流。
 *
 * <p>要完成消息摘要计算，请在调用此摘要输入流的<a href>Read</a>方法之后，对关联的消息摘要调用其中一个<code>Digest</code>方法。
 *      
 * <p>可以打开或关闭该流(请参阅<a href>on</a>)。当它打开时，调用<code>Read</code>会更新消息摘要。
 * 但当它关闭时，消息摘要不会更新。默认情况下，流处于打开状态。
 *
 * 请注意，摘要对象只能计算一个摘要(请参阅MessageDigest)，因此为了计算中间摘要，调用方应该在摘要对象上保留一个句柄，
 * 并为要计算的每个摘要克隆它，保持原始摘要不变。
 *
 * @see MessageDigest
 * 
 * @see DigestOutputStream
 *
 * @version 1.30 01/12/12
 * @author Benjamin Renaud 
 */

public class DigestInputStream extends FilterInputStream {

    /* NOTE: This should be made a generic UpdaterInputStream */

    /* Are we on or off? */
    private boolean on = true;

    /**
     * The message digest associated with this stream.
     */
    protected MessageDigest digest;

    /**
     * 使用指定的输入流和消息摘要创建摘要输入流。
     *
     * @param stream the input stream.
     *
     * @param digest the message digest to associate with this stream.
     */
    public DigestInputStream(InputStream stream, MessageDigest digest) {
	super(stream);
	setMessageDigest(digest);
    }

    /**
     * Returns the message digest associated with this stream.
     *
     * @return the message digest associated with this stream.
     */
    public MessageDigest getMessageDigest() {
	return digest;
    }    

    /**
     * Associates the specified message digest with this stream.
     *
     * @param digest the message digest to be associated with this stream.  
     */
    public void setMessageDigest(MessageDigest digest) {
	this.digest = digest;
    }

    /**
     * 读取一个字节，并更新消息摘要(如果摘要功能打开)。也就是说，此方法从输入流中读取一个字节，一直阻塞到实际读取该字节。
     * 如果摘要函数为ON(参见<a href>on</a>)，则此方法将在与该流关联的消息摘要上调用<code>update</code>，并将读取的字节传递给它。
     *
     * @return the byte read.
     *
     * @exception IOException if an I/O error occurs.
     * 
     * @see MessageDigest#update(byte) 
     */
    public int read() throws IOException {
	int ch = in.read();
	if (on && ch != -1) {
	    digest.update((byte)ch);
	}
	return ch;
    }

    /**
     * 读入字节数组，并更新消息摘要(如果摘要功能打开)。也就是说，此方法从偏移量<code>off</code>开始，
     * 将最多<code>len</code>字节从输入流读取到数组<code>b</code>。此方法会一直阻塞，直到实际读取数据为止。
     * 如果摘要函数为ON(参见<a href>on</a>)，则此方法将在与该流关联的消息摘要上调用<code>update</code>，并将数据传递给它。
     *
     * @param b	the array into which the data is read.
     *
     * @param off 应放置数据的<code>b</code>的起始偏移量。
     *
     * @param len 要从输入流读取到b的最大字节数，从偏移量<code>off</code>开始。
     *
     * @return 实际读取的字节数。如果在读取<code>len</code>字节之前到达流的末尾，则该值小于<code>len</code>。
     * 如果由于调用时已经到达流的末尾而没有读取字节，则返回。
     *
     * @exception IOException if an I/O error occurs.
     * 
     * @see MessageDigest#update(byte[], int, int) 
     */
    public int read(byte[] b, int off, int len) throws IOException {
	int result = in.read(b, off, len);
	if (on && result != -1) {
	    digest.update(b, off, result);
	}
	return result;
    }

    /**
     * 打开或关闭摘要功能。默认设置为启用。当它打开时，调用<a href>Read</a>会导致更新消息摘要。但当它关闭时，消息摘要不会更新。
     *   
     * @param on true to turn the digest function on, false to turn
     * it off.
     */
    public void on(boolean on) {
	this.on = on;
    }
	
    /**
     * 打印此摘要输入流及其关联的消息摘要对象的字符串表示形式。
     */
     public String toString() {
	 return "[Digest Input Stream] " + digest.toString();
     }
}	


  

